#include "desktop.h"
#include "desktop_test.h"
#include "desktop_data.h"

#include <unistd.h>
#include <sys/types.h>  /* basic system data types */
#include <sys/socket.h> /* basic socket definitions */
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#define __USE_MISC 1
#include <net/if.h>
#include <arpa/inet.h>    /* inet(3) functions */
#include <sys/epoll.h>    /* epoll function */
#include <fcntl.h>        /* nonblocking */
#include <sys/resource.h> /*setrlimit */
#include <errno.h>
#include <sys/time.h>
#include <sys/ioctl.h>

#define _MAXLINE 256
#define _MAX_MESSAGE_LENGTH 256
#define _MAX_TCPC_CLIENT 10

// #define MAXPORT 2

autoCheck_Typedef autoCheck;
static int connfd = -1;

void auto_setState(uint8_t state)
{
    autoCheck.state = state;
}

int auto_init()
{
    auto_setState(Auto_Null);
    return 1;
}

int auto_start()
{
    auto_setState(Auto_Init);
    return 1;
}

void auto_stop()
{
    auto_setState(Auto_Over);
}

static int setnonblocking(int sockfd)
{
    if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0) | O_NONBLOCK) == -1)
    {
        return -1;
    }
    return 0;
}

int checkCom(int RouteId)
{
    char portName[10] = {0};
    sprintf(portName, "COM%d\0", RouteId);
    printf("%s自检\n", portName);
    char *sendStr = "01 03 00 00 00 05 85 C9";
    cfg_pu_t *pu = g_cfg->g_coll_link;
    while (pu)
    {
        if (strcmp(pu->port.type, portName) == 0)
        {
            break;
        }
        pu = pu->next;
    }
    if (pu == NULL)
    {
        UTIL_LOG_E(pu, "find %s null!", portName);
        return -1;
    }

    msg_t push;
    push.type = MSG_TYPE_PASS;
    push.ts = util_hw_get_systs();
    push.su = "";
    push.ch = "";
    msg_pass_t pass;
    memset(&pass, 0, sizeof(msg_pass_t));
    pass.cnt = util_format_hex(sendStr, pass.stream);
    push.value = (void *)&pass;
    UTIL_LOG_I(pu, "uart: %s pass package:%s---->", portName, sendStr);

    dlmodule_t *dlmodule = (dlmodule_t *)pu->hanlder.dlmodule;
    int ret = dlmodule->msg(pu, &push);
    if (ret == 0 && pass.cnt != 0)
        return 1;
    else
        return 0;
}

int checkLora()
{
    char *portName = "LORA";
    printf("%s自检\n", portName);
    char *sendStr = "01 03 00 00 00 05 85 C9";
    
    cfg_pu_t *pu = g_cfg->g_coll_link;
    while (pu)
    {
        if (strcmp(pu->port.type, portName) == 0)
        {
            break;
        }
        pu = pu->next;
    }
    if (pu == NULL)
    {
        UTIL_LOG_E(pu, "find %s null!", portName);
        return -1;
    }

    msg_t push;
    push.type = MSG_TYPE_PASS;
    push.ts = util_hw_get_systs();
    push.su = "";
    push.ch = "";
    msg_pass_t pass;
    memset(&pass, 0, sizeof(msg_pass_t));
    pass.cnt = util_format_hex(sendStr, pass.stream);
    push.value = (void *)&pass;
    UTIL_LOG_I(pu, "lora: %s pass package:%s---->", portName, sendStr);

    dlmodule_t *dlmodule = (dlmodule_t *)pu->hanlder.dlmodule;
    int ret = dlmodule->msg(pu, &push);
    if (ret == 0 && pass.cnt != 0)
        return 1;
    else
        return 0;
}

int auto_Check_Pro(cfg_pu_t *pu)
{
    // static uint16_t _lora_exist = 1;
    // static uint16_t maxport = 2; // com1 com2
    // static uint16_t cnt = 0;
    // static uint16_t waitCnt = 0;
    // uint8_t i = 0;
    // api_t *api = (api_t *)pu->hanlder.api;
    // int64_t state_4G = 0;

    // switch (autoCheck.state)
    // {
    // case Auto_Null:
    //     break;

    // case Auto_Init:
    // {
    //     UTIL_LOG_I(pu, "进入自动测试模式");
    //     autoCheck.CheckTime = 0;
    //     autoCheck.buf = (char *)malloc(sizeof(char) * 1024);
    //     memset(autoCheck.buf, 0, 1024);

    //     char *type = g_cfg->g_basic->product;

    //     if (0 == strncmp(type, "ANet-1E1S", 9))
    //         maxport = 1;
    //     else
    //         maxport = 2;

    //     for (i = 0; i < maxport + 1; i++)
    //     {
    //         autoCheck.Route[i].RouteId = i + 1;
    //         autoCheck.Route[i].TxCnt = 0;
    //         autoCheck.Route[i].RxCnt = 0;
    //     }
    //     auto_setState(Auto_SendData);
    //     break;
    // }

    // case Auto_SendData:
    // {
    //     // uint8_t testbuf[10] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x05, 0x85, 0xC9};
    //     for (i = 0; i < maxport; ++i)
    //     {
    //         autoCheck.Route[i].TxCnt++;
    //         if (checkCom(i + 1) == 1)
    //         {
    //             autoCheck.Route[i].RxCnt++;
    //         }
    //     }

    //     autoCheck.Route[maxport].TxCnt++;
    //     if (checkLora() == 1)
    //     {
    //         autoCheck.Route[maxport].RxCnt++;
    //     }

    //     if (autoCheck.SendCnt++ > 2)
    //     {
    //         autoCheck.SendCnt = 0;
    //         UTIL_LOG_I(pu, "串口/LoRa 自检结束");
    //         auto_setState(Auto_View);
    //     }
    // }
    // break;

    // case Auto_View:
    // {
    //     char tempbuf[128] = {0};
    //     time_t sec = 0, time_utc = 0;
    //     time(&sec);
    //     struct tm *ptm, *ptm_local;
    //     ptm_local = localtime(&time_utc);
    //     int time_zone = (ptm_local->tm_hour > 12) ? (ptm_local->tm_hour -= 24) : ptm_local->tm_hour;
    //     ptm = localtime(&sec);
    //     memset(autoCheck.buf, 0, 1024);

    //     sprintf(tempbuf, ">>>>>>>>>>>>>>>>>>>>自动测试<<<<<<<<<<<<<<<<<<<<\r\n");
    //     strcat(autoCheck.buf, tempbuf);

    //     sprintf(tempbuf, "系统时间:20%02d-%02d-%02d %02d:%02d:%02d UTC:%d\r\n", ptm->tm_year - 100, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, time_zone);
    //     strcat(autoCheck.buf, tempbuf);

    //     sprintf(tempbuf, "设备型号:%s\r\n", "AWT200");
    //     strcat(autoCheck.buf, tempbuf);
    //     sprintf(tempbuf, "设备序列号:%s\r\n", "ABCD0123456789");
    //     strcat(autoCheck.buf, tempbuf);
    //     sprintf(tempbuf, "软件版本:Code:%s Version:%s\r\n", "0000", "1000");
    //     strcat(autoCheck.buf, tempbuf);

    //     for (i = 0; i < maxport; ++i)
    //     {
    //         sprintf(tempbuf, "RS485_%d Send:%d Rec:%d\r\n", i + 1, autoCheck.Route[0].TxCnt, autoCheck.Route[0].RxCnt);
    //         strcat(autoCheck.buf, tempbuf);
    //     }

    //     sprintf(tempbuf, "lora Send:%d Rec:%d\r\n", autoCheck.Route[maxport].TxCnt, autoCheck.Route[maxport].RxCnt);
    //     strcat(autoCheck.buf, tempbuf);

    //     /*4G state*/

    //     rb_mem_t *mem = api->get_g_rb_mem("gateway", "GSMState");
    //     if (NULL == mem)
    //     {
    //         state_4G = -1;
    //     }
    //     else
    //     {
    //         util_ch_get_integer_val(mem->ch, &state_4G);
    //     }
    //     if (state_4G >= 0 && state_4G < 5)
    //         sprintf(tempbuf, "4G State:%s\r\n", GSMState_Table[state_4G]);
    //     else
    //         sprintf(tempbuf, "4G State:error\r\n");
    //     strcat(autoCheck.buf, tempbuf);

    //     // memset(autoCheck.buf, 0, 1024);
    //     /*
    //     if (USBSDData.USBInsertFlag)
    //     {
    //         sprintf(tempbuf, "U盘: 已插入\r\n");
    //         strcat(autoCheck.buf, tempbuf);
    //         autoCheck.USBInsertFlag = 1;
    //     }
    //     else
    //     {
    //         sprintf(tempbuf, "U盘: 未插入\r\n");
    //         strcat(autoCheck.buf, tempbuf);
    //     }

    //     if (USBSDData.SDInitSuccessFlag)
    //     {
    //         sprintf(tempbuf, "SD卡: 已插入\r\n");
    //         strcat(autoCheck.buf, tempbuf);
    //         autoCheck.SDInsertFlag = 1;
    //     }
    //     else
    //     {
    //         sprintf(tempbuf, "SD卡: 未插入\r\n");
    //         strcat(autoCheck.buf, tempbuf);
    //     }

    //     if (SysPer.gsm == 1)
    //     {
    //         sprintf(tempbuf, "4G State:");
    //         strcat(autoCheck.buf, tempbuf);

    //         memset(tempbuf, 0, 128);
    //         net_GetRunState(Net4G, (uint8_t *)tempbuf);
    //         strcat(autoCheck.buf, tempbuf);

    //         // strcat(autoCheck.buf,"\r\n");
    //     }
    //     else if (SysPer.wifi == 1)
    //     {
    //         sprintf(tempbuf, "WIFI State:");
    //         strcat(autoCheck.buf, tempbuf);

    //         memset(tempbuf, 0, 128);
    //         net_GetRunState(NetWIFI, (uint8_t *)tempbuf);
    //         strcat(autoCheck.buf, tempbuf);

    //         // strcat(autoCheck.buf,"\r\n");
    //     }
    //     */
    //     auto_setState(Auto_Wait);
    // }
    // break;
    // case Auto_Wait:
    //     if (waitCnt++ > 60)
    //     {
    //         waitCnt = 0;
    //         auto_setState(Auto_SendData);
    //     }
    //     break;
    // case Auto_Over:
    //     UTIL_LOG_I(pu, "自动测试结束");
    //     free(autoCheck.buf);
    //     autoCheck.buf = NULL;

    //     auto_setState(Auto_Null);
    //     return 1;
    // default:
    //     break;
    // }

    return 0;
}

static int handle(cfg_pu_t *pu, int connfd)
{
    int nread;
    uint8_t req[_MAXLINE];
    uint8_t rsp[_MAX_MESSAGE_LENGTH];

    nread = read(connfd, req, _MAXLINE); // 读取客户端socket流

    if (nread == 0)
    {
        UTIL_LOG_W(pu,"60003 client %d close the connection\n", connfd);
        auto_stop();
        close(connfd);
        return -1;
    }
    else if (nread < 0)
    {
        perror("60003 read error");
        auto_stop();
        close(connfd);
        return -1;
    }
}

// void *AutoCheck(void *param)
// {
//     cfg_pu_t *pu = (cfg_pu_t *)param;

//     UTIL_LOG_D(pu, "AutoCheck Init ...");
//     // printf("autoCheckState %d\n", autoCheck.state);
//     while (1)
//     {
//         msleep(500);
//         if(0 < auto_Check_Pro(pu))
//         {
//             UTIL_LOG_I(pu,"Auto Check End...");
//         }
//         if (autoCheck.buf != NULL && strlen(autoCheck.buf) > 0)
//         {
//             UTIL_LOG_I(pu, "autoCheck: len:%d, get buf%s\n", strlen(autoCheck.buf), autoCheck.buf);

//             pu_param_t *param = (pu_param_t *)pu->hanlder.param;
//             rt_slist_t *e;
//             pthread_mutex_lock(&param->lock);
//             rt_slist_for_each(e, &param->socket60003)
//             {
//                 tcps_t *socket = rt_slist_entry(e, tcps_t, slist);

//                 printf("socket=====>>>>>>%d\n", socket->s);

//                 int ret = tcps_write(pu, socket, autoCheck.buf, 1024);
//                 if (ret == -1)
//                 {
//                     UTIL_LOG_E(pu, "autoCheck: send to desktop_test error,%s", strerror(errno));
//                 }
//             }
//             memset(autoCheck.buf, 0, 1024);
//             int i = 0;
//             // MAXPORT default 2
//             // for (i = 0; i < 2 + 1; i++)
//             for (i = 0; i < 9; i++)
//             {
//                 autoCheck.Route[i].TxCnt = 0;
//                 autoCheck.Route[i].RxCnt = 0;
//             }

//             auto_start();
//             pthread_mutex_unlock(&param->lock);

//         }
//     }

//     pthread_exit(NULL);
// }


void desktop_test_run(cfg_pu_t *pu)
{
    auto_init();

    // pthread_t thread; // autoCheck
    // int err = pthread_create(&thread, NULL, AutoCheck, pu);
    // if (err)
    // {
    //     UTIL_LOG_E(pu, "Failed to create autoCheck thread!");
    // }
    // pthread_detach(thread);

    // cfg_enet_t *tcp = (cfg_enet_t *)pu->port.setting;
    char m_ip[32] = {0};
    char m_port[8] = {0};

    int listenq = 1024;
    int listenfd, connfd, kdpfd, nfds, n, nread, curfds;
    struct sockaddr_in servaddr, cliaddr;
    socklen_t socklen = sizeof(struct sockaddr_in);
    struct epoll_event ev;
    struct epoll_event events[10];
    struct rlimit rt;
    // char buf[MAXLINE];

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;

    servaddr.sin_addr.s_addr = inet_addr(g_cfg->g_basic->ip);
    servaddr.sin_port = htons(60003);
    strcpy(m_ip, g_cfg->g_basic->ip);
    sprintf(m_port, "%d\0", 60003);
    // }
    int flags = SOCK_STREAM;

#ifdef SOCK_CLOEXEC
    flags |= SOCK_CLOEXEC;
#endif
    listenfd = socket(PF_INET, flags, IPPROTO_TCP);
    if (listenfd == -1)
    {
        UTIL_LOG_E(pu, "can't create socket file");
        pthread_exit(NULL);
    }

    int opt = 1;
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
                   (char *)&opt, sizeof(opt)) == -1)
    {
        close(listenfd);
        pthread_exit(NULL);
    }

    if (setnonblocking(listenfd) < 0)
    {
        UTIL_LOG_E(pu, "setnonblock error");
    }

    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) == -1)
    {
        UTIL_LOG_E(pu, "bind %s:%s error,%s", m_ip, m_port, strerror(errno));
        close(listenfd);
        pthread_exit(NULL);
    }

    // 主进程关闭后，同时关闭socket
    fcntl(listenfd, F_SETFD, FD_CLOEXEC);

    if (listen(listenfd, listenq) == -1)
    {
        UTIL_LOG_E(pu, "listen error");
        close(listenfd);
        pthread_exit(NULL);
    }

    /*创建epoll句柄，把监听 socket 加入到 epoll 集合里 */
    kdpfd = epoll_create(10);
    ev.events = EPOLLIN | EPOLLET;
    ev.data.fd = listenfd;
    if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < 0)
    {
        UTIL_LOG_E(pu, "epoll set insertion error: fd=%d", listenfd);
        pthread_exit(NULL);
    }

    curfds = 1;
    UTIL_LOG_D(pu, "epollserver:%s.%s startup\n", m_ip, m_port);
    for (;;)
    {
        /* 等待有事件发生 */
        nfds = epoll_wait(kdpfd, events, curfds, -1);
        if (nfds == -1)
        {
            UTIL_LOG_E(pu, "epoll_wait error");
            continue;
        }

        /* 处理所有事件 */
        for (n = 0; n < nfds; ++n)
        {
            if (events[n].data.fd == listenfd)
            {
                connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &socklen);

                if (connfd < 0)
                {
                    UTIL_LOG_E(pu, "accept error");
                    continue;
                }
                auto_init();
                UTIL_LOG_D(pu, "60003 accept form %s:%d", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
                // pu->hanlder.param = inet_ntoa(cliaddr.sin_addr);
                if (curfds >= 10)
                {
                    UTIL_LOG_E(pu, "too many connection, more than %d", 10);
                    close(connfd);
                    continue;
                }

                if (setnonblocking(connfd) < 0)
                {
                    UTIL_LOG_E(pu, "setnonblocking error");
                    close(connfd);
                    continue;
                }

                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = connfd;

                if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connfd, &ev) < 0)
                {
                    UTIL_LOG_E(pu, "add socket '%d' to epoll failed: %s", connfd, strerror(errno));
                    close(connfd);
                    continue;
                }

                // 加入新的socket
                pu_param_t *param = (pu_param_t *)pu->hanlder.param;
                strncpy(param->destIp, inet_ntoa(cliaddr.sin_addr), 32);

                tcps_t *new = malloc(sizeof(tcps_t));
                new->len = 0;
                new->s = connfd;

                new->debug = param->debug;
                rt_slist_append(&param->socket60003, &new->slist);

                curfds++;
                continue;
            }

            // 处理客户端请求
            if (handle(pu, events[n].data.fd) < 0)
            {
                auto_stop();
                epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd, &ev);
                curfds--;

                pu_param_t *param = (pu_param_t *)pu->hanlder.param;
                rt_slist_t *e;
                pthread_mutex_lock(&param->lock);
                rt_slist_for_each(e, &param->socket60003)
                {
                    tcps_t *socket = rt_slist_entry(e, tcps_t, slist);
                    if (socket->s == events[n].data.fd)
                    {
                        param->socket60003 = *rt_slist_remove(&param->socket60003, &socket->slist);
                        free(socket);
                    }
                }
                pthread_mutex_unlock(&param->lock);
            }
        }
    }

    close(listenfd);
    pthread_exit(NULL);
}

